package top.codedance.iotp.tools.terminal.ui;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import top.codedance.iotp.common.util.SystemUtil;
import top.codedance.iotp.tools.terminal.TerminalApplication;
import top.codedance.iotp.tools.terminal.bean.ComConnectParam;
import top.codedance.iotp.tools.terminal.comer.CallOwner;
import top.codedance.iotp.tools.terminal.comer.ComClient;

import javax.swing.*;
import javax.xml.bind.DatatypeConverter;
import java.awt.event.ItemEvent;
import java.io.*;
import java.net.URL;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author xuedianfu
 */
public class UploadFile extends javax.swing.JDialog implements CallOwner {
    private static ExecutorService pool = Executors.newCachedThreadPool();
    private ShellFrame sf;
    private JSONObject currentConnectionParam;
    private JSONObject connectData = new JSONObject();
    private DefaultComboBoxModel<String> dlmB;
    private static short RUNNER_TYPE = 2;
    private static int i = 0;
    private static boolean isCancel = false;
    private static int taskId = i;
    private CountDownLatch latch = new CountDownLatch(0);

    /**
     * Creates new form UploadFile
     */
    public UploadFile(ShellFrame sf) {
        super(sf, true);
        this.sf = sf;
        initComponents();
        URL url = Thread.currentThread().getContextClassLoader().getResource("logo.gif");
        ImageIcon icon = new ImageIcon(url);
        setIconImage(icon.getImage());
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setLocationRelativeTo(this.sf);
        setTitle("代码飞舞采控系统-上传文件");

        jpb_status.setStringPainted(true);
        jpb_status.setBorderPainted(true);

        initList();
    }

    public void initList() {
        dlmB = new DefaultComboBoxModel<>();
        this.jcb_connections.setModel(dlmB);
        initListData();
    }

    public void initListData() {
        String s = SystemUtil.readTempFile(ConnectionManager.CONNECTION_TMP_FILENAME);
        if (null != s && !s.isEmpty()) {
            connectData = JSON.parseObject(s);
            dlmB.removeAllElements();
            Set<Map.Entry<String, Object>> entries = connectData.entrySet();
            JSONObject jo;
            JSONObject comJo;
            for (Map.Entry<String, Object> entry : entries) {
                jo = (JSONObject) entry.getValue();
                if (jo.containsKey("type") && jo.getString("type").equals("com") && jo.containsKey("manage") && jo.getBoolean("manage")) {
                    dlmB.addElement(entry.getKey());
                }
            }
            this.jcb_connections.repaint();
            String key = (String) jcb_connections.getSelectedItem();
            currentConnectionParam = this.connectData.getJSONObject(key);
        }
    }

    private int getTaskId() {
        return i++;
    }

    private void comSendCmd(String cmd) {
        if (currentConnectionParam == null || currentConnectionParam.isEmpty()) {
            JOptionPane.showMessageDialog(rootPane, "请选取连接配置。");
            return;
        }
        if (!currentConnectionParam.containsKey("com") || currentConnectionParam.getString("com").isEmpty()) {
            JOptionPane.showMessageDialog(rootPane, "请选取Com口的连接配置。");
            return;
        }
        JSONObject com = currentConnectionParam.getJSONObject("com");
        String comName = com.getString("value");
        String btl = currentConnectionParam.getString("btl");
        String sjw = currentConnectionParam.getString("sjw");
        String tzw = currentConnectionParam.getString("tzw");
        String xyw = currentConnectionParam.getString("xyw");
        if (!sf.ccs.containsKey(comName)) {
            createComClient(comName, btl, sjw, tzw, xyw);
        } else {
            ComClient comClient = sf.ccs.get(comName);
            comClient.setOwner(this);
        }
        ComClient comClient = sf.ccs.get(comName);
        comClient.send(cmd);
    }

    private void createComClient(String comName, String btl, String sjw, String tzw, String xyw) {
        sf.ccs.put(comName, new ComClient(this, new ComConnectParam(comName, Integer.parseInt(btl), Integer.parseInt(sjw), Integer.parseInt(tzw), Integer.parseInt(xyw))));
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        jtf_source = new javax.swing.JTextField();
        jb_brower = new javax.swing.JButton();
        jLabel3 = new javax.swing.JLabel();
        jtf_target = new javax.swing.JTextField();
        jLabel4 = new javax.swing.JLabel();
        jpb_status = new javax.swing.JProgressBar();
        jb_upload = new javax.swing.JButton();
        jb_cancel = new javax.swing.JButton();
        jLabel5 = new javax.swing.JLabel();
        jcb_connections = new javax.swing.JComboBox<>();
        jLabel6 = new javax.swing.JLabel();
        jtf_filename = new javax.swing.JTextField();
        jLabel7 = new javax.swing.JLabel();
        jcb_replace = new javax.swing.JCheckBox();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setResizable(false);

        jLabel1.setText("文件上传");

        jLabel2.setText("文件：");
        jLabel2.setToolTipText("");

        jtf_source.setEditable(false);

        jb_brower.setText("浏览...");
        jb_brower.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jb_browerActionPerformed(evt);
            }
        });

        jLabel3.setText("上传目录：");
        jLabel3.setToolTipText("");

        jtf_target.setToolTipText("文件保存的全路径");

        jLabel4.setText("进度：");

        jb_upload.setText("上传");
        jb_upload.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jb_uploadActionPerformed(evt);
            }
        });

        jb_cancel.setText("取消");
        jb_cancel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jb_cancelActionPerformed(evt);
            }
        });

        jLabel5.setText("连接：");

        jcb_connections.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                jcb_connectionsItemStateChanged(evt);
            }
        });

        jLabel6.setText("目标文件名：");

        jtf_filename.setToolTipText("目标文件名，可以改");

        jLabel7.setText("冲突：");

        jcb_replace.setText("覆盖同位置同名文件");
        jcb_replace.setActionCommand("覆盖同位置同名文件");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel7)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(jb_upload)
                        .addGap(18, 18, 18)
                        .addComponent(jb_cancel))
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(jLabel2)
                                    .addComponent(jLabel3)
                                    .addComponent(jLabel5))
                                .addGap(21, 21, 21)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                                    .addComponent(jcb_connections, javax.swing.GroupLayout.Alignment.LEADING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                    .addComponent(jtf_source, javax.swing.GroupLayout.DEFAULT_SIZE, 393, Short.MAX_VALUE)
                                    .addComponent(jtf_target)))
                            .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(jLabel6)
                                    .addComponent(jLabel4))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addGroup(layout.createSequentialGroup()
                                        .addGap(0, 0, Short.MAX_VALUE)
                                        .addComponent(jLabel1)
                                        .addGap(180, 180, 180))
                                    .addComponent(jpb_status, javax.swing.GroupLayout.DEFAULT_SIZE, 396, Short.MAX_VALUE)
                                    .addComponent(jtf_filename)
                                    .addGroup(layout.createSequentialGroup()
                                        .addComponent(jcb_replace)
                                        .addGap(0, 0, Short.MAX_VALUE)))))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jb_brower)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel1)
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel5)
                    .addComponent(jcb_connections, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel2)
                    .addComponent(jtf_source, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jb_brower))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel3)
                    .addComponent(jtf_target, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel6)
                    .addComponent(jtf_filename, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jpb_status, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jb_upload)
                    .addComponent(jb_cancel)
                    .addComponent(jLabel7)
                    .addComponent(jcb_replace, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void doUploadFile(File file) {
        pool.submit(() -> {
            try {
                taskId = getTaskId();
                String filename = jtf_filename.getText();
                String target = jtf_target.getText();
                long contentLength = file.length();
                InputStream in = new FileInputStream(file);
                int dataIndex = 0;
                int readLength = -1;
                byte[] tmp = new byte[1024 * 4];
                long completeContentLength = 0;
                while ((readLength = in.read(tmp)) != -1 && !isCancel) {
                    boolean await = latch.await(3, TimeUnit.SECONDS);
                    if (await) {
                        latch = new CountDownLatch(1);
                        byte[] filebody = Arrays.copyOf(tmp, readLength);
                        JSONObject command = new JSONObject();
                        JSONObject cmd = new JSONObject();
                        cmd.put("runner", RUNNER_TYPE);
                        cmd.put("opration", 0);
                        cmd.put("taskId", taskId);
                        cmd.put("dataIndex", dataIndex);
                        cmd.put("contentLength", contentLength);
                        cmd.put("bodyLength", readLength);
                        cmd.put("body", DatatypeConverter.printHexBinary(filebody));
                        cmd.put("cover", jcb_replace.isSelected());
                        cmd.put("target", target);
                        cmd.put("filename", filename.replaceAll("\\s+", ""));
                        command.put("cmd", cmd);
                        comSendCmd(command.toJSONString());
                        dataIndex++;
                        completeContentLength += readLength;
                        Double percentage = Math.floor(completeContentLength * 1.0 / contentLength * 100);
                        TerminalApplication.syslogInfo("dataIndex: " + dataIndex);
                        TerminalApplication.syslogInfo("Download complete :" + percentage + "%");
                        if(completeContentLength >= contentLength){
                            break;
                        }
                    } else {
                        JOptionPane.showMessageDialog(this.getRootPane(), "文件上传失败!");
                        latch.countDown();
                        break;
                    }
                }
                in.close();
                jb_upload.setEnabled(true);
                jb_cancel.setEnabled(false);
            } catch (Exception e) {
                TerminalApplication.syslogInfo(e.getMessage());
                JOptionPane.showMessageDialog(this.getRootPane(), "文件上传失败!");
            } finally {
                isCancel = false;
            }
        });
    }

    @Override
    public String getOwnerClassName() {
        return this.getClass().getTypeName();
    }

    @Override
    public void appendResult(String data) {
        TerminalApplication.syslogInfo(data);
        try {
            JSONObject jsonObject = JSON.parseObject(data);
            if (jsonObject.containsKey("taskId") && jsonObject.containsKey("percentage")) {
                int tid = jsonObject.getIntValue("taskId");
                if (tid == taskId) {
                    int percentage = jsonObject.getIntValue("percentage");
                    jpb_status.setValue(percentage);
                    if (percentage == 100) {
                        JOptionPane.showMessageDialog(this.getRootPane(), "上传成功");
                    }
                }
            }
        } catch (Exception e) {
            TerminalApplication.syslogInfo(e.getMessage());
        } finally {
            latch.countDown();
        }
    }

    @Override
    public void appendError(String data) {
        if (data != null) {
            JSONObject jsonObject = JSON.parseObject(data);
            JOptionPane.showMessageDialog(this.getRootPane(), "上传失败: " + jsonObject.getString("msg"));
            jb_upload.setEnabled(true);
            jb_cancel.setEnabled(false);
            jpb_status.setValue(0);
        }
    }

    private void jb_browerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jb_browerActionPerformed
        JFileChooser jfc = new JFileChooser();
        jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        int i = jfc.showOpenDialog(this);
        if (i == JFileChooser.APPROVE_OPTION) {
            File selectedFile = jfc.getSelectedFile();
            if (selectedFile.exists() && selectedFile.isFile()) {
                jtf_source.setText(selectedFile.getAbsolutePath());
                jtf_filename.setText(selectedFile.getName().replaceAll("\\s+", ""));
            } else {
                JOptionPane.showMessageDialog(this.getRootPane(), "请选取一个文件");
            }
        }
    }//GEN-LAST:event_jb_browerActionPerformed

    private void jb_uploadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jb_uploadActionPerformed
        if (jtf_target.getText().isEmpty()) {
            JOptionPane.showMessageDialog(this.getRootPane(), "请输入文件上传的路径");
            return;
        }
        int i = JOptionPane.showConfirmDialog(rootPane, "确定要上传吗。");
        if (JOptionPane.YES_OPTION == i) {
            jpb_status.setValue(0);
            doUploadFile(new File(jtf_source.getText()));
            jb_upload.setEnabled(false);
            jb_cancel.setEnabled(true);
        }
    }//GEN-LAST:event_jb_uploadActionPerformed

    private void jb_cancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jb_cancelActionPerformed
        int i = JOptionPane.showConfirmDialog(rootPane, "确定要取消吗。");
        if (JOptionPane.YES_OPTION == i) {
            isCancel = true;
            try {
                Thread.sleep(500);
            } catch (Exception e) {
            }
            JSONObject command = new JSONObject();
            JSONObject cmd = new JSONObject();
            cmd.put("runner", RUNNER_TYPE);
            cmd.put("opration", 1);
            cmd.put("taskId", taskId);
            command.put("cmd", cmd);
            comSendCmd(command.toJSONString());
            JOptionPane.showMessageDialog(this.getRootPane(), "已取消");
            jpb_status.setValue(0);
            jb_upload.setEnabled(true);
            jb_cancel.setEnabled(false);
        }
    }//GEN-LAST:event_jb_cancelActionPerformed

    private void jcb_connectionsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_jcb_connectionsItemStateChanged
        if (evt.getStateChange() == ItemEvent.SELECTED) {
            String key = (String) jcb_connections.getSelectedItem();
            currentConnectionParam = this.connectData.getJSONObject(key);
        }
    }//GEN-LAST:event_jcb_connectionsItemStateChanged

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JButton jb_brower;
    private javax.swing.JButton jb_cancel;
    private javax.swing.JButton jb_upload;
    private javax.swing.JComboBox<String> jcb_connections;
    private javax.swing.JCheckBox jcb_replace;
    private javax.swing.JProgressBar jpb_status;
    private javax.swing.JTextField jtf_filename;
    private javax.swing.JTextField jtf_source;
    private javax.swing.JTextField jtf_target;
    // End of variables declaration//GEN-END:variables
}
